/********************************************************
 * ADO.NET 2.0 Data Provider for SQLite Version 3.X
 * Written by Robert Simpson (robert@blackcastlesoft.com)
 *
 * Released to the public domain, use at your own risk!
 ********************************************************/

namespace System.Data.SQLite
{
    using System;
    using System.Data.Common;
    using System.Globalization;

#if !PLATFORM_COMPACTFRAMEWORK
    using System.Reflection;
    using System.Runtime.Serialization;
    using System.Security.Permissions;
#endif

    /// <summary>
    /// SQLite exception class.
    /// </summary>
#if !PLATFORM_COMPACTFRAMEWORK
    [Serializable()]
    public sealed class SQLiteException : DbException, ISerializable
#else
  public sealed class SQLiteException : Exception
#endif
    {
        #region Private Constants
        /// <summary>
        /// This value was copied from the "WinError.h" file included with the
        /// Platform SDK for Windows 10.
        /// </summary>
        private const int FACILITY_SQLITE = 1967;
        #endregion

        ///////////////////////////////////////////////////////////////////////////

        private readonly SQLiteErrorCode _errorCode;

        ///////////////////////////////////////////////////////////////////////////

#if !PLATFORM_COMPACTFRAMEWORK
        /// <summary>
        /// Private constructor for use with serialization.
        /// </summary>
        /// <param name="info">
        /// Holds the serialized object data about the exception being thrown.
        /// </param>
        /// <param name="context">
        /// Contains contextual information about the source or destination.
        /// </param>
        private SQLiteException(SerializationInfo info, StreamingContext context)
          : base(info, context)
        {
            _errorCode = (SQLiteErrorCode)info.GetInt32("errorCode");

            Initialize();
        }
#endif

        ///////////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Public constructor for generating a SQLite exception given the error
        /// code and message.
        /// </summary>
        /// <param name="errorCode">
        /// The SQLite return code to report.
        /// </param>
        /// <param name="message">
        /// Message text to go along with the return code message text.
        /// </param>
        public SQLiteException(SQLiteErrorCode errorCode, string message)
          : base(GetStockErrorMessage(errorCode, message))
        {
            _errorCode = errorCode;

            Initialize();
        }

        ///////////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Public constructor that uses the base class constructor for the error
        /// message.
        /// </summary>
        /// <param name="message">Error message text.</param>
        public SQLiteException(string message)
          : this(SQLiteErrorCode.Unknown, message)
        {
            // do nothing.
        }

        ///////////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Public constructor that uses the default base class constructor.
        /// </summary>
        public SQLiteException()
            : base()
        {
            Initialize();
        }

        ///////////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Public constructor that uses the base class constructor for the error
        /// message and inner exception.
        /// </summary>
        /// <param name="message">Error message text.</param>
        /// <param name="innerException">The original (inner) exception.</param>
        public SQLiteException(string message, Exception innerException)
          : base(message, innerException)
        {
            Initialize();
        }

        ///////////////////////////////////////////////////////////////////////////

#if !PLATFORM_COMPACTFRAMEWORK
        /// <summary>
        /// Adds extra information to the serialized object data specific to this
        /// class type.  This is only used for serialization.
        /// </summary>
        /// <param name="info">
        /// Holds the serialized object data about the exception being thrown.
        /// </param>
        /// <param name="context">
        /// Contains contextual information about the source or destination.
        /// </param>
        [SecurityPermission(
          SecurityAction.LinkDemand,
          Flags = SecurityPermissionFlag.SerializationFormatter)]
        public override void GetObjectData(
          SerializationInfo info,
          StreamingContext context)
        {
            if (info != null)
                info.AddValue("errorCode", _errorCode);

            base.GetObjectData(info, context);
        }
#endif

        ///////////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Gets the associated SQLite result code for this exception as a
        /// <see cref="SQLiteErrorCode" />.  This property returns the same
        /// underlying value as the <see cref="ErrorCode" /> property.
        /// </summary>
        public SQLiteErrorCode ResultCode
        {
            get { return _errorCode; }
        }

        ///////////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Gets the associated SQLite return code for this exception as an
        /// <see cref="Int32" />.  For desktop versions of the .NET Framework,
        /// this property overrides the property of the same name within the
        /// <see cref="System.Runtime.InteropServices.ExternalException" />
        /// class.  This property returns the same underlying value as the
        /// <see cref="ResultCode" /> property.
        /// </summary>
#if !PLATFORM_COMPACTFRAMEWORK
        public override int ErrorCode
#else
    public int ErrorCode
#endif
        {
            get { return (int)_errorCode; }
        }

        ///////////////////////////////////////////////////////////////////////////

        /// <summary>
        /// This method performs extra initialization tasks.  It may be called by
        /// any of the constructors of this class.  It must not throw exceptions.
        /// </summary>
        private void Initialize()
        {
            if (HResult == unchecked((int)0x80004005)) /* E_FAIL */
            {
                int? localHResult = GetHResultForErrorCode(ResultCode);

                if (localHResult != null)
                    HResult = (int)localHResult;
            }
        }

        ///////////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Maps a Win32 error code to an HRESULT.
        /// </summary>
        /// <param name="errorCode">
        /// The specified Win32 error code.  It must be within the range of zero
        /// (0) to 0xFFFF (65535).
        /// </param>
        /// <param name="success">
        /// Non-zero if the HRESULT should indicate success; otherwise, zero.
        /// </param>
        /// <returns>
        /// The integer value of the HRESULT.
        /// </returns>
        private static int MakeHResult(
            int errorCode,
            bool success
            )
        {
            return (errorCode & 0xFFFF) | FACILITY_SQLITE |
                (success ? 0 : unchecked((int)0x80000000));
        }

        ///////////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Attempts to map the specified <see cref="SQLiteErrorCode" /> onto an
        /// existing HRESULT -OR- a Win32 error code wrapped in an HRESULT.  The
        /// mappings may not have perfectly matching semantics; however, they do
        /// have the benefit of being unique within the context of this exception
        /// type.
        /// </summary>
        /// <param name="errorCode">
        /// The <see cref="SQLiteErrorCode" /> to map.
        /// </param>
        /// <returns>
        /// The integer HRESULT value -OR- null if there is no known mapping.
        /// </returns>
        private static int? GetHResultForErrorCode(
            SQLiteErrorCode errorCode
            )
        {
            switch (errorCode & SQLiteErrorCode.NonExtendedMask)
            {
                case SQLiteErrorCode.Ok:
                    {
                        return 0; /* S_OK */
                    }
                case SQLiteErrorCode.Error:
                    {
                        return MakeHResult(0x001F, false); /* ERROR_GEN_FAILURE */
                    }
                case SQLiteErrorCode.Internal:
                    {
                        return unchecked((int)0x8000FFFF); /* E_UNEXPECTED */
                    }
                case SQLiteErrorCode.Perm:
                    {
                        return MakeHResult(0x0005, false); /* ERROR_ACCESS_DENIED */
                    }
                case SQLiteErrorCode.Abort:
                    {
                        return unchecked((int)0x80004004); /* E_ABORT */
                    }
                case SQLiteErrorCode.Busy:
                    {
                        return MakeHResult(0x00AA, false); /* ERROR_BUSY */
                    }
                case SQLiteErrorCode.Locked:
                    {
                        return MakeHResult(0x00D4, false); /* ERROR_LOCKED */
                    }
                case SQLiteErrorCode.NoMem:
                    {
                        return MakeHResult(0x000E, false); /* ERROR_OUTOFMEMORY */
                    }
                case SQLiteErrorCode.ReadOnly:
                    {
                        return MakeHResult(0x1779, false); /* ERROR_FILE_READ_ONLY */
                    }
                case SQLiteErrorCode.Interrupt:
                    {
                        return MakeHResult(0x04C7, false); /* ERROR_CANCELLED */
                    }
                case SQLiteErrorCode.IoErr:
                    {
                        return MakeHResult(0x045D, false); /* ERROR_IO_DEVICE */
                    }
                case SQLiteErrorCode.Corrupt:
                    {
                        return MakeHResult(0x054E, false); /* ERROR_INTERNAL_DB_CORRUPTION */
                    }
                case SQLiteErrorCode.NotFound:
                    {
                        return MakeHResult(0x0032, false); /* ERROR_NOT_SUPPORTED */
                    }
                case SQLiteErrorCode.Full:
                    {
                        return MakeHResult(0x0070, false); /* ERROR_DISK_FULL */
                    }
                case SQLiteErrorCode.CantOpen:
                    {
                        return MakeHResult(0x03F3, false); /* ERROR_CANTOPEN */
                    }
                case SQLiteErrorCode.Protocol:
                    {
                        return MakeHResult(0x05B4, false); /* ERROR_TIMEOUT */
                    }
                case SQLiteErrorCode.Empty:
                    {
                        return MakeHResult(0x10D2, false); /* ERROR_EMPTY */
                    }
                case SQLiteErrorCode.Schema:
                    {
                        return MakeHResult(0x078B, false); /* ERROR_CONTEXT_EXPIRED */
                    }
                case SQLiteErrorCode.TooBig:
                    {
                        return unchecked((int)0x800288C5); /* TYPE_E_SIZETOOBIG */
                    }
                case SQLiteErrorCode.Constraint:
                    {
                        return MakeHResult(0x202F, false); /* ERROR_DS_CONSTRAINT_VIOLATION */
                    }
                case SQLiteErrorCode.Mismatch:
                    {
                        return MakeHResult(0x065D, false); /* ERROR_DATATYPE_MISMATCH */
                    }
                case SQLiteErrorCode.Misuse:
                    {
                        return MakeHResult(0x0649, false); /* ERROR_INVALID_HANDLE_STATE */
                    }
                case SQLiteErrorCode.NoLfs:
                    {
                        return MakeHResult(0x0646, false); /* ERROR_UNKNOWN_FEATURE */
                    }
                case SQLiteErrorCode.Auth:
                    {
                        return MakeHResult(0x078F, false); /* ERROR_AUTHENTICATION_FIREWALL_FAILED */
                    }
                case SQLiteErrorCode.Format:
                    {
                        return MakeHResult(0x000B, false); /* ERROR_BAD_FORMAT */
                    }
                case SQLiteErrorCode.Range:
                    {
                        return unchecked((int)0x80028CA1); /* TYPE_E_OUTOFBOUNDS */
                    }
                case SQLiteErrorCode.NotADb:
                    {
                        return MakeHResult(0x0570, false); /* ERROR_FILE_CORRUPT */
                    }
                case SQLiteErrorCode.Notice:
                case SQLiteErrorCode.Warning:
                case SQLiteErrorCode.Row:
                case SQLiteErrorCode.Done:
                    {
                        //
                        // NOTE: These result codes are not errors, per se;
                        //       therefore, mask off all HRESULT bits that
                        //       are not part of the "code" portion (e.g.
                        //       the severity, facility, etc).  This will
                        //       have the effect of creating an HRESULT
                        //       that indicates success, while (hopefully)
                        //       preserving the specified result code.  At
                        //       the time this method was written (2018-02),
                        //       no SQLite result codes were outside of the
                        //       supported range for HRESULT codes (e.g.
                        //       0x0000 to 0xFFFF, inclusive), which made
                        //       the following masking operation a harmless
                        //       NOOP.
                        //
                        return MakeHResult((int)errorCode, true);
                    }
            }

            return null;
        }

        ///////////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Returns the error message for the specified SQLite return code.
        /// </summary>
        /// <param name="errorCode">The SQLite return code.</param>
        /// <returns>The error message or null if it cannot be found.</returns>
        private static string GetErrorString(
            SQLiteErrorCode errorCode
            )
        {
#if !PLATFORM_COMPACTFRAMEWORK
            //
            // HACK: This must be done via reflection in order to prevent
            //       the RuntimeHelpers.PrepareDelegate method from over-
            //       eagerly attempting to locate the new (and optional)
            //       sqlite3_errstr() function in the SQLite core library
            //       because it happens to be in the static call graph for
            //       the AppDomain.DomainUnload event handler registered
            //       by the SQLiteLog class.
            //
            BindingFlags flags = BindingFlags.Static |
                BindingFlags.NonPublic | BindingFlags.InvokeMethod;

            return typeof(SQLite3).InvokeMember("GetErrorString",
                flags, null, null, new object[] { errorCode }) as string;
#else
        return SQLite3.GetErrorString(errorCode);
#endif
        }

        ///////////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Returns the composite error message based on the SQLite return code
        /// and the optional detailed error message.
        /// </summary>
        /// <param name="errorCode">The SQLite return code.</param>
        /// <param name="message">Optional detailed error message.</param>
        /// <returns>Error message text for the return code.</returns>
        private static string GetStockErrorMessage(
            SQLiteErrorCode errorCode,
            string message
            )
        {
            return HelperMethods.StringFormat(
                CultureInfo.CurrentCulture,
                "{0}{1}{2}",
                GetErrorString(errorCode),
#if !NET_COMPACT_20
            Environment.NewLine, message).Trim();
#else
            "\r\n", message).Trim();
#endif
        }

        ///////////////////////////////////////////////////////////////////////////

        #region System.Object Overrides
        public override string ToString()
        {
            return HelperMethods.StringFormat(
                CultureInfo.CurrentCulture, "code = {0} ({1}), message = {2}",
                _errorCode, (int)_errorCode, base.ToString());
        }
        #endregion
    }

    /// <summary>
    /// SQLite error codes.  Actually, this enumeration represents a return code,
    /// which may also indicate success in one of several ways (e.g. SQLITE_OK,
    /// SQLITE_ROW, and SQLITE_DONE).  Therefore, the name of this enumeration is
    /// something of a misnomer.
    /// </summary>
    public enum SQLiteErrorCode
    {
        /// <summary>
        /// The error code is unknown.  This error code
        /// is only used by the managed wrapper itself.
        /// </summary>
        Unknown = -1,
        /// <summary>
        /// Successful result
        /// </summary>
        Ok /* 0 */,
        /// <summary>
        /// SQL error or missing database
        /// </summary>
        Error /* 1 */,
        /// <summary>
        /// Internal logic error in SQLite
        /// </summary>
        Internal /* 2 */,
        /// <summary>
        /// Access permission denied
        /// </summary>
        Perm /* 3 */,
        /// <summary>
        /// Callback routine requested an abort
        /// </summary>
        Abort /* 4 */,
        /// <summary>
        /// The database file is locked
        /// </summary>
        Busy /* 5 */,
        /// <summary>
        /// A table in the database is locked
        /// </summary>
        Locked /* 6 */,
        /// <summary>
        /// A malloc() failed
        /// </summary>
        NoMem /* 7 */,
        /// <summary>
        /// Attempt to write a readonly database
        /// </summary>
        ReadOnly /* 8 */,
        /// <summary>
        /// Operation terminated by sqlite3_interrupt()
        /// </summary>
        Interrupt /* 9 */,
        /// <summary>
        /// Some kind of disk I/O error occurred
        /// </summary>
        IoErr /* 10 */,
        /// <summary>
        /// The database disk image is malformed
        /// </summary>
        Corrupt /* 11 */,
        /// <summary>
        /// Unknown opcode in sqlite3_file_control()
        /// </summary>
        NotFound /* 12 */,
        /// <summary>
        /// Insertion failed because database is full
        /// </summary>
        Full /* 13 */,
        /// <summary>
        /// Unable to open the database file
        /// </summary>
        CantOpen /* 14 */,
        /// <summary>
        /// Database lock protocol error
        /// </summary>
        Protocol /* 15 */,
        /// <summary>
        /// Database is empty
        /// </summary>
        Empty /* 16 */,
        /// <summary>
        /// The database schema changed
        /// </summary>
        Schema /* 17 */,
        /// <summary>
        /// String or BLOB exceeds size limit
        /// </summary>
        TooBig /* 18 */,
        /// <summary>
        /// Abort due to constraint violation
        /// </summary>
        Constraint /* 19 */,
        /// <summary>
        /// Data type mismatch
        /// </summary>
        Mismatch /* 20 */,
        /// <summary>
        /// Library used incorrectly
        /// </summary>
        Misuse /* 21 */,
        /// <summary>
        /// Uses OS features not supported on host
        /// </summary>
        NoLfs /* 22 */,
        /// <summary>
        /// Authorization denied
        /// </summary>
        Auth /* 23 */,
        /// <summary>
        /// Auxiliary database format error
        /// </summary>
        Format /* 24 */,
        /// <summary>
        /// 2nd parameter to sqlite3_bind out of range
        /// </summary>
        Range /* 25 */,
        /// <summary>
        /// File opened that is not a database file
        /// </summary>
        NotADb /* 26 */,
        /// <summary>
        /// Notifications from sqlite3_log()
        /// </summary>
        Notice /* 27 */,
        /// <summary>
        /// Warnings from sqlite3_log()
        /// </summary>
        Warning /* 28 */,
        /// <summary>
        /// sqlite3_step() has another row ready
        /// </summary>
        Row = 100,
        /// <summary>
        /// sqlite3_step() has finished executing
        /// </summary>
        Done, /* 101 */
              /// <summary>
              /// Used to mask off extended result codes
              /// </summary>
        NonExtendedMask = 0xFF,

        /////////////////////////////////////////////////////////////////////////
        // BEGIN EXTENDED RESULT CODES
        /////////////////////////////////////////////////////////////////////////

        /// <summary>
        /// A collation sequence was referenced by a schema and it cannot be
        /// found.
        /// </summary>
        Error_Missing_CollSeq = (Error | (1 << 8)),
        /// <summary>
        /// An internal operation failed and it may succeed if retried.
        /// </summary>
        Error_Retry = (Error | (2 << 8)),
        /// <summary>
        /// A file read operation failed.
        /// </summary>
        IoErr_Read = (IoErr | (1 << 8)),
        /// <summary>
        /// A file read operation returned less data than requested.
        /// </summary>
        IoErr_Short_Read = (IoErr | (2 << 8)),
        /// <summary>
        /// A file write operation failed.
        /// </summary>
        IoErr_Write = (IoErr | (3 << 8)),
        /// <summary>
        /// A file synchronization operation failed.
        /// </summary>
        IoErr_Fsync = (IoErr | (4 << 8)),
        /// <summary>
        /// A directory synchronization operation failed.
        /// </summary>
        IoErr_Dir_Fsync = (IoErr | (5 << 8)),
        /// <summary>
        /// A file truncate operation failed.
        /// </summary>
        IoErr_Truncate = (IoErr | (6 << 8)),
        /// <summary>
        /// A file metadata operation failed.
        /// </summary>
        IoErr_Fstat = (IoErr | (7 << 8)),
        /// <summary>
        /// A file unlock operation failed.
        /// </summary>
        IoErr_Unlock = (IoErr | (8 << 8)),
        /// <summary>
        /// A file lock operation failed.
        /// </summary>
        IoErr_RdLock = (IoErr | (9 << 8)),
        /// <summary>
        /// A file delete operation failed.
        /// </summary>
        IoErr_Delete = (IoErr | (10 << 8)),
        /// <summary>
        /// Not currently used.
        /// </summary>
        IoErr_Blocked = (IoErr | (11 << 8)),
        /// <summary>
        /// Out-of-memory during a file operation.
        /// </summary>
        IoErr_NoMem = (IoErr | (12 << 8)),
        /// <summary>
        /// A file existence/status operation failed.
        /// </summary>
        IoErr_Access = (IoErr | (13 << 8)),
        /// <summary>
        /// A check for a reserved lock failed.
        /// </summary>
        IoErr_CheckReservedLock = (IoErr | (14 << 8)),
        /// <summary>
        /// A file lock operation failed.
        /// </summary>
        IoErr_Lock = (IoErr | (15 << 8)),
        /// <summary>
        /// A file close operation failed.
        /// </summary>
        IoErr_Close = (IoErr | (16 << 8)),
        /// <summary>
        /// A directory close operation failed.
        /// </summary>
        IoErr_Dir_Close = (IoErr | (17 << 8)),
        /// <summary>
        /// A shared memory open operation failed.
        /// </summary>
        IoErr_ShmOpen = (IoErr | (18 << 8)),
        /// <summary>
        /// A shared memory size operation failed.
        /// </summary>
        IoErr_ShmSize = (IoErr | (19 << 8)),
        /// <summary>
        /// A shared memory lock operation failed.
        /// </summary>
        IoErr_ShmLock = (IoErr | (20 << 8)),
        /// <summary>
        /// A shared memory map operation failed.
        /// </summary>
        IoErr_ShmMap = (IoErr | (21 << 8)),
        /// <summary>
        /// A file seek operation failed.
        /// </summary>
        IoErr_Seek = (IoErr | (22 << 8)),
        /// <summary>
        /// A file delete operation failed because it does not exist.
        /// </summary>
        IoErr_Delete_NoEnt = (IoErr | (23 << 8)),
        /// <summary>
        /// A file memory mapping operation failed.
        /// </summary>
        IoErr_Mmap = (IoErr | (24 << 8)),
        /// <summary>
        /// The temporary directory path could not be obtained.
        /// </summary>
        IoErr_GetTempPath = (IoErr | (25 << 8)),
        /// <summary>
        /// A path string conversion operation failed.
        /// </summary>
        IoErr_ConvPath = (IoErr | (26 << 8)),
        /// <summary>
        /// Reserved.
        /// </summary>
        IoErr_VNode = (IoErr | (27 << 8)),
        /// <summary>
        /// An attempt to authenticate failed.
        /// </summary>
        IoErr_Auth = (IoErr | (28 << 8)),
        /// <summary>
        /// An attempt to begin a file system transaction failed.
        /// </summary>
        IoErr_Begin_Atomic = (IoErr | (29 << 8)),
        /// <summary>
        /// An attempt to commit a file system transaction failed.
        /// </summary>
        IoErr_Commit_Atomic = (IoErr | (30 << 8)),
        /// <summary>
        /// An attempt to rollback a file system transaction failed.
        /// </summary>
        IoErr_Rollback_Atomic = (IoErr | (31 << 8)),
        /// <summary>
        /// A database table is locked in shared-cache mode.
        /// </summary>
        Locked_SharedCache = (Locked | (1 << 8)),
        /// <summary>
        /// A virtual table in the database is locked.
        /// </summary>
        Locked_Vtab = (Locked | (2 << 8)),
        /// <summary>
        /// A database file is locked due to a recovery operation.
        /// </summary>
        Busy_Recovery = (Busy | (1 << 8)),
        /// <summary>
        /// A database file is locked due to snapshot semantics.
        /// </summary>
        Busy_Snapshot = (Busy | (2 << 8)),
        /// <summary>
        /// A database file cannot be opened because no temporary directory is available.
        /// </summary>
        CantOpen_NoTempDir = (CantOpen | (1 << 8)),
        /// <summary>
        /// A database file cannot be opened because its path represents a directory.
        /// </summary>
        CantOpen_IsDir = (CantOpen | (2 << 8)),
        /// <summary>
        /// A database file cannot be opened because its full path could not be obtained.
        /// </summary>
        CantOpen_FullPath = (CantOpen | (3 << 8)),
        /// <summary>
        /// A database file cannot be opened because a path string conversion operation failed.
        /// </summary>
        CantOpen_ConvPath = (CantOpen | (4 << 8)),
        /// <summary>
        /// A virtual table is malformed.
        /// </summary>
        Corrupt_Vtab = (Corrupt | (1 << 8)),
        /// <summary>
        /// A required sequence table is missing or corrupt.
        /// </summary>
        Corrupt_Sequence = (Corrupt | (2 << 8)),
        /// <summary>
        /// A database file is read-only due to a recovery operation.
        /// </summary>
        ReadOnly_Recovery = (ReadOnly | (1 << 8)),
        /// <summary>
        /// A database file is read-only because a lock could not be obtained.
        /// </summary>
        ReadOnly_CantLock = (ReadOnly | (2 << 8)),
        /// <summary>
        /// A database file is read-only because it needs rollback processing.
        /// </summary>
        ReadOnly_Rollback = (ReadOnly | (3 << 8)),
        /// <summary>
        /// A database file is read-only because it was moved while open.
        /// </summary>
        ReadOnly_DbMoved = (ReadOnly | (4 << 8)),
        /// <summary>
        /// The shared-memory file is read-only and it should be read-write.
        /// </summary>
        ReadOnly_CantInit = (ReadOnly | (5 << 8)),
        /// <summary>
        /// Unable to create journal file because the directory is read-only.
        /// </summary>
        ReadOnly_Directory = (ReadOnly | (6 << 8)),
        /// <summary>
        /// An operation is being aborted due to rollback processing.
        /// </summary>
        Abort_Rollback = (Abort | (2 << 8)),
        /// <summary>
        /// A CHECK constraint failed.
        /// </summary>
        Constraint_Check = (Constraint | (1 << 8)),
        /// <summary>
        /// A commit hook produced a unsuccessful return code.
        /// </summary>
        Constraint_CommitHook = (Constraint | (2 << 8)),
        /// <summary>
        /// A FOREIGN KEY constraint failed.
        /// </summary>
        Constraint_ForeignKey = (Constraint | (3 << 8)),
        /// <summary>
        /// Not currently used.
        /// </summary>
        Constraint_Function = (Constraint | (4 << 8)),
        /// <summary>
        /// A NOT NULL constraint failed.
        /// </summary>
        Constraint_NotNull = (Constraint | (5 << 8)),
        /// <summary>
        /// A PRIMARY KEY constraint failed.
        /// </summary>
        Constraint_PrimaryKey = (Constraint | (6 << 8)),
        /// <summary>
        /// The RAISE function was used by a trigger-program.
        /// </summary>
        Constraint_Trigger = (Constraint | (7 << 8)),
        /// <summary>
        /// A UNIQUE constraint failed.
        /// </summary>
        Constraint_Unique = (Constraint | (8 << 8)),
        /// <summary>
        /// Not currently used.
        /// </summary>
        Constraint_Vtab = (Constraint | (9 << 8)),
        /// <summary>
        /// A ROWID constraint failed.
        /// </summary>
        Constraint_RowId = (Constraint | (10 << 8)),
        /// <summary>
        /// Frames were recovered from the WAL log file.
        /// </summary>
        Notice_Recover_Wal = (Notice | (1 << 8)),
        /// <summary>
        /// Pages were recovered from the journal file.
        /// </summary>
        Notice_Recover_Rollback = (Notice | (2 << 8)),
        /// <summary>
        /// An automatic index was created to process a query.
        /// </summary>
        Warning_AutoIndex = (Warning | (1 << 8)),
        /// <summary>
        /// User authentication failed.
        /// </summary>
        Auth_User = (Auth | (1 << 8)),
        /// <summary>
        /// Success.  Prevents the extension from unloading until the process
        /// terminates.
        /// </summary>
        Ok_Load_Permanently = (Ok | (1 << 8))
    }
}
